package com.micro.ai.auth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.micro.ai.auth.entity.DictData;
import com.micro.ai.auth.entity.DictI18n;
import com.micro.ai.auth.mapper.DictDataMapper;
import com.micro.ai.auth.mapper.DictI18nMapper;
import com.micro.ai.auth.service.DictDataService;
import com.micro.ai.auth.entity.DictType;
import com.micro.ai.auth.service.DictTypeService;
import com.micro.ai.commons.exception.BusinessException;
import com.micro.ai.commons.util.IdUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 字典数据服务实现类
 *
 * @author micro-ai
 * @since 2025-01-29
 */
@Slf4j
@Service
public class DictDataServiceImpl extends ServiceImpl<DictDataMapper, DictData> implements DictDataService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private DictTypeService dictTypeService;
    
    @Autowired
    private DictI18nMapper dictI18nMapper;

    private static final String DICT_CACHE_PREFIX = "dict:data:";
    private static final long CACHE_EXPIRE_TIME = 24 * 60 * 60; // 24小时

    @Override
    public IPage<DictData> getDictDataPage(Page<DictData> page, String dictTypeId, String label, String value, String status) {
        return baseMapper.selectDictDataPage(page, dictTypeId, label, value, status);
    }

    @Override
    public List<DictData> getByDictTypeId(String dictTypeId) {
        return baseMapper.selectByDictTypeId(dictTypeId);
    }

    @Override
    public List<DictData> getByDictTypeCode(String dictTypeCode, String tenantId) {
        // 先从缓存获取
        String cacheKey = DICT_CACHE_PREFIX + dictTypeCode + ":" + tenantId;
        @SuppressWarnings("unchecked")
        List<DictData> cachedData = (List<DictData>) redisTemplate.opsForValue().get(cacheKey);
        
        if (cachedData != null) {
            return cachedData;
        }

        // 缓存未命中，从数据库查询
        List<DictData> dictDataList = baseMapper.selectByDictTypeCode(dictTypeCode, tenantId);
        
        // 存入缓存
        if (dictDataList != null && !dictDataList.isEmpty()) {
            redisTemplate.opsForValue().set(cacheKey, dictDataList, CACHE_EXPIRE_TIME, TimeUnit.SECONDS);
        }

        return dictDataList;
    }

    @Override
    public DictData getByDictTypeCodeAndValue(String dictTypeCode, String value, String tenantId) {
        return baseMapper.selectByDictTypeCodeAndValue(dictTypeCode, value, tenantId);
    }

    @Override
    public List<DictData> getActiveDictData(String tenantId) {
        return baseMapper.selectActiveDictData(tenantId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createDictData(DictData dictData) {
        // 检查值是否已存在
        if (existsByValue(dictData.getDictTypeId(), dictData.getValue(), null)) {
            throw new BusinessException("字典值已存在");
        }

        // 设置ID和创建时间
        dictData.setId(IdUtils.generateId());
        dictData.setCreatedAt(LocalDateTime.now());
        dictData.setUpdatedAt(LocalDateTime.now());

        boolean result = save(dictData);
        
        // 刷新缓存 - 需要先获取字典类型编码
        if (result) {
            DictType dictType = dictTypeService.getById(dictData.getDictTypeId());
            if (dictType != null) {
                refreshDictCache(dictType.getCode(), dictType.getTenantId() != null ? dictType.getTenantId() : "tn_system");
            }
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateDictData(DictData dictData) {
        // 检查值是否已存在（排除自己）
        if (existsByValue(dictData.getDictTypeId(), dictData.getValue(), dictData.getId())) {
            throw new BusinessException("字典值已存在");
        }

        // 设置更新时间
        dictData.setUpdatedAt(LocalDateTime.now());

        boolean result = updateById(dictData);
        
        // 刷新缓存
        if (result) {
            DictType dictType = dictTypeService.getById(dictData.getDictTypeId());
            if (dictType != null) {
                refreshDictCache(dictType.getCode(), dictType.getTenantId() != null ? dictType.getTenantId() : "tn_system");
            }
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteDictData(String id) {
        // 检查字典数据是否存在（直接使用SQL查询，不应用逻辑删除过滤）
        DictData dictData = baseMapper.selectByIdIgnoreLogic(id);
        if (dictData == null || dictData.getDeletedAt() != null) {
            throw new BusinessException("字典数据不存在或已被删除");
        }

        // 1. 级联删除关联的国际化数据
        List<DictI18n> i18nList = dictI18nMapper.selectByDictDataId(id);
        if (i18nList != null && !i18nList.isEmpty()) {
            List<String> i18nIds = i18nList.stream()
                    .map(DictI18n::getId)
                    .collect(java.util.stream.Collectors.toList());
            log.info("删除字典数据，级联删除 {} 条国际化数据: dictDataId={}", i18nIds.size(), id);
            // 批量删除国际化数据
            for (String i18nId : i18nIds) {
                dictI18nMapper.deleteById(i18nId);
            }
        }

        // 2. 物理删除字典数据（使用直接SQL删除，绕过逻辑删除；数据库外键会自动级联删除国际化数据，这里是显式删除以记录日志）
        int deleteResult = baseMapper.deleteByIdPhysical(id);
        log.info("物理删除字典数据: id={}, result={}", id, deleteResult > 0);
        
        // 刷新缓存
        if (deleteResult > 0) {
            DictType dictType = dictTypeService.getById(dictData.getDictTypeId());
            if (dictType != null) {
                refreshDictCache(dictType.getCode(), dictType.getTenantId() != null ? dictType.getTenantId() : "tn_system");
            }
        }

        if (deleteResult == 0) {
            throw new BusinessException("删除字典数据失败");
        }

        return deleteResult > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchDeleteDictData(List<String> ids) {
        if (ids == null || ids.isEmpty()) {
            return true;
        }

        // 批量级联删除：先删除关联的国际化数据
        for (String id : ids) {
            List<DictI18n> i18nList = dictI18nMapper.selectByDictDataId(id);
            if (i18nList != null && !i18nList.isEmpty()) {
                List<String> i18nIds = i18nList.stream()
                        .map(DictI18n::getId)
                        .collect(java.util.stream.Collectors.toList());
                log.info("批量删除字典数据，级联删除国际化数据: dictDataId={}, count={}", id, i18nIds.size());
                // 批量删除国际化数据
                for (String i18nId : i18nIds) {
                    dictI18nMapper.deleteById(i18nId);
                }
            }
        }

        // 批量物理删除字典数据（使用直接SQL删除，绕过逻辑删除；数据库外键会自动级联删除国际化数据，这里是显式删除以记录日志）
        int totalDeleteCount = 0;
        for (String id : ids) {
            int deleteResult = baseMapper.deleteByIdPhysical(id);
            if (deleteResult > 0) {
                totalDeleteCount++;
            }
        }
        log.info("批量物理删除字典数据: count={}, result={}", ids.size(), totalDeleteCount);
        
        return totalDeleteCount > 0;
    }

    @Override
    public boolean existsByValue(String dictTypeId, String value, String excludeId) {
        LambdaQueryWrapper<DictData> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DictData::getDictTypeId, dictTypeId);
        wrapper.eq(DictData::getValue, value);
        wrapper.ne(excludeId != null, DictData::getId, excludeId);
        wrapper.isNull(DictData::getDeletedAt);

        return count(wrapper) > 0;
    }

    @Override
    public void refreshDictCache(String dictTypeCode, String tenantId) {
        try {
            // 删除相关缓存
            String cacheKey = DICT_CACHE_PREFIX + dictTypeCode + ":" + tenantId;
            redisTemplate.delete(cacheKey);
            
            log.info("字典缓存已刷新: {}", cacheKey);
        } catch (Exception e) {
            log.error("刷新字典缓存失败: {}", e.getMessage(), e);
        }
    }
}
